home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / batchut / test.zip / TEST.C < prev    next >
C/C++ Source or Header  |  1994-04-14  |  8KB  |  277 lines

  1. /*
  2.  * MS-DOS Batch utility - test file/directory status
  3.  *
  4.  * Unix-like test program returns true or false according
  5.  * to a conditional expression.
  6.  *
  7.  * syntax:  test <expression>
  8.  *
  9.  * test evaluates the expression <expression> and, if its value
  10.  * is true, returns a non-zero (true) exit status; otherwise, a
  11.  * zero (false) exit status is returned.  test returns a
  12.  * zero if there are no arguments.
  13.  
  14.  * The following primitives are used to construct an expression.
  15.  *
  16.  * primitive operators testing one file:
  17.  *
  18.  *    -f|b|c|e|d|s|z|r|w|x filename
  19.  *
  20.  *   -e  true if filename exists
  21.  *   -b  true if filename exists and is a block special device
  22.  *   -c  true if filename exists and is a character special device
  23.  *   -d  true if filename exists and is a directory
  24.  *   -f  true if filename exists and is a regular file
  25.  *   -s  true if filename exists and has a size greater than zero
  26.  *   -z  true if filename exists and has a zero length (empty)
  27.  *   -r  true if filename exists and is readable
  28.  *   -w  true if filename exists and is writable
  29.  *   -x  true if filename exists and is executable
  30.  *        (MS-DOS: file extension = .COM, .EXE, .BAT, or .BTM )
  31.  *
  32.  *   -m[n] filename
  33.  *    True if filename exists and has been modified in n days (default=1).
  34.  *
  35.  * primitive operators comparing two files:
  36.  *
  37.  *    -D|N|S file1 file2
  38.  *
  39.  *   -D  true of file1 has same date as file2 and both files exist
  40.  *   -N  true if file1 is newer than file2 and both files exist
  41.  *   -S  true if file1 has same size as file2 and both files exist
  42.  *
  43.  * Logical operators:
  44.  *
  45.  * The above primitives may be combined with the following operators:
  46.  *
  47.  *  cond1 [-a] cond2  True if both cond1 and cond2 are true.
  48.  *                    The -a is not required.  It is implied by
  49.  *                    the juxtaposition by the two conditions.
  50.  *
  51.  *  cond1 -o cond2    True if either cond1 or cond2 is true
  52.  *                    (-o is the OR operator).
  53.  *
  54.  *  ! condition       True if the condition is false
  55.  *                    (! is the unary NOT operator).
  56.  *
  57.  * AND/OR/NOT operators are processed left to right with no precedence;
  58.  * e.g. "! c1 -o c2 -a c3" is evaluated as (!c1 -o c2) -a c3.
  59.  *
  60.  *
  61.  *  return errorlevel = 1 if the tested expression is true
  62.  *  otherwise return 0 (conditions not meet or error flag set).
  63.  *
  64.  *****************************************************************************
  65.  *
  66.  * Developed by Jason Mathews,    NASA/Goddard Space Flight Center
  67.  *                <mathews@nssdca.gsfc.nasa.gov>
  68.  *
  69.  * Copyright (C) 1992-94 by Jason Mathews.  Permission is granted to any
  70.  * individual or institution to use, copy or redistribute this software so long
  71.  * as it is not sold for profit, provided this copyright notice is retained.
  72.  *
  73.  * Modification history:
  74.  *  11/17/92 -    Basic file & logical operators of UNIX test command.
  75.  *  11/28/92 -    Added binary operator -N file1 file2 to test if
  76.  *         file1 is newer than file2 by comparing the time stamp,
  77.  *        added -n testing if a file has been modified in n days.
  78.  *  4/30/93  -  Added 'S' file size equal operator.
  79.  *  4/14/94  -  Added 'D' file date equal operator.
  80.  *
  81.  *****************************************************************************/
  82.  
  83. #include <stdio.h>
  84. #include <stdlib.h>
  85. #include <time.h>
  86. #include <sys/stat.h>
  87.  
  88. #ifdef __MSDOS__
  89. #include <string.h>
  90. #endif
  91.  
  92. #ifdef unix
  93. #define bool unsigned char
  94. #else
  95. typedef unsigned char bool;
  96. #endif
  97.  
  98. #define true  1
  99. #define false 0
  100.  
  101. int main (int argc, char**argv)
  102. {
  103.   int rc, i = 1;
  104.   int count = 0;    /* number of expressions evaluated */
  105.   bool newCond;        /* new condition */
  106.   bool cond    = true;    /* start with return condition as false
  107.              * and set to true only if expression is true
  108.              */
  109.   bool notFlag = false; /* NOT operator */
  110.   bool orFlag  = false; /* OR operator  */
  111.   char sw_char;        /* switch character */
  112.   long value;
  113.   struct stat statbuf, statbuf2;
  114.  
  115.   if (argc < 2) return 0;    /* no arguments */
  116.  
  117.   do
  118.   {
  119.     newCond = true;    /* assume condition is true and
  120.              * set false only if condition is false.
  121.              */
  122.     if (*argv[i] == '!')
  123.     {
  124.         notFlag = true;
  125.         i++;
  126.     }
  127.  
  128.     if (argc - i < 2)
  129.     {
  130.   expect_arg:
  131.     fprintf(stderr, "test: argument expected\n");
  132.     return 0;
  133.     }
  134.  
  135.     if (*argv[i] != '-')
  136.     {
  137.     sw_char = *argv[i];
  138.   unknown_arg:
  139.     fprintf(stderr, "test: unknown argument %c\n", sw_char);
  140.     return 0;
  141.     }
  142.  
  143.     sw_char = argv[i][1];
  144.     switch (sw_char) {
  145.       case 'a':
  146.     orFlag = false;          /* reset orFlag to false */
  147.     i++;                /* move to next argument */
  148.     /* if (!count) cond = true; */    /* default */
  149.     continue;             /* get next argument */
  150.  
  151.       case 'o':
  152.     orFlag = true;
  153.     /* if first expression then start as false */
  154.     if (!count) cond = false;
  155.     i++;
  156.     continue;
  157.     } /* switch */
  158.  
  159.     rc = stat( argv[i+1], &statbuf );
  160.  
  161.     /* binary operator - check if 2nd argument exists */
  162.     if (sw_char=='N' || sw_char=='S' || sw_char=='D')
  163.     {
  164.     if (++i+1 >= argc || *argv[i+1]=='-') goto expect_arg; /* error */
  165.     rc |= stat(argv[i+1], &statbuf2);
  166.     }
  167.  
  168.     if ( rc==0 )        /* file exists? */
  169.       switch (sw_char) {
  170.  case 'N': /* true if filename1 is newer than filename2 and both exist */
  171.     if (statbuf.st_mtime <= statbuf2.st_mtime)   /* not newer? */
  172.         newCond = false;
  173.     break;
  174.  
  175.  case 'S': /* true if filename1 is same size as filename2 and both exist */
  176.     if (statbuf.st_size != statbuf2.st_size)
  177.           newCond = false;
  178.     break;
  179.  
  180.  case 'D': /* true if file1 has same date as file2 and both exist */
  181.     if (statbuf.st_mtime != statbuf2.st_mtime)
  182.           newCond = false;
  183.     break;
  184.  
  185.  case 'm': /* true if filename exists and has been modified in n days */
  186.     /* also true if the time stamp is newer than the system clock */
  187.     value = (argv[i][2]) ? value = atol(argv[i]+2) : 1;
  188.     /* false if the time difference is greater than n days */
  189.     if ((time(0) - statbuf.st_mtime) > (86400L * value))
  190.         newCond = false;
  191.     break;
  192.  
  193.  case 'd': /* true if filename exists and is a directory */
  194.     if (!(statbuf.st_mode & S_IFDIR)) newCond = false;
  195.     break;
  196.  
  197.  case 'f': /* true if filename exists and is a regular file */
  198.     if (!(statbuf.st_mode & S_IFREG)) newCond = false;
  199.     break;
  200.  
  201.  case 's': /* true if filename exists and has a size greater than zero */
  202.     if (statbuf.st_size == 0) newCond = false;
  203.     break;
  204.  
  205.  case 'z': /* true if filename exists and has a zero length (empty) */
  206.     if (statbuf.st_size > 0) newCond = false;
  207.     break;
  208.  
  209. #ifndef __MSDOS__    /* always true for MS-DOS */
  210.  case 'r': /* true if filename exists and is readable */
  211.     if (!(statbuf.st_mode & S_IREAD)) newCond = false;
  212.     break;
  213. #endif
  214.  
  215.  case 'w': /* true if filename exists and is writable */
  216.     if (!(statbuf.st_mode & S_IWRITE)) newCond = false;
  217.     break;
  218.  
  219.   /* Executable flag is only true for directories in MS-DOS.
  220.    * However, it should return true only if the file extension is
  221.    * .EXE, .COM, .BAT, or .BTM
  222.    */
  223.  case 'x': /* true if filename exists and is executable */
  224. #ifdef __MSDOS__
  225.     {
  226.       char *filename = argv[i+1];
  227.       while (*filename && *filename != '.') filename++;
  228.       strlwr(filename);
  229.       if (strcmp(filename, ".exe") && strcmp(filename, ".com") &&
  230.           strcmp(filename, ".bat") && strcmp(filename, ".btm"))
  231.         newCond = false;
  232.     }
  233. #else
  234.     if (!(statbuf.st_mode & S_IEXEC)) newCond = false;
  235. #endif
  236.     break;
  237.  
  238.  case 'b': /* true if filename exists and is a block special device */
  239.     if (!(statbuf.st_mode & S_IFBLK)) newCond = false;
  240.     break;
  241.  
  242.  case 'c': /* true if filename exist and is a character special device */
  243.     if (!(statbuf.st_mode & S_IFCHR)) newCond = false;
  244.     break;
  245.  
  246.  case 'e':    /* true if filename exists */
  247.     break;
  248.  
  249.  default:
  250.     goto unknown_arg;
  251.     } /* switch */
  252.     else    /* rc!=0: filename doesn't exist, so file condition is false */
  253.     {
  254.     newCond = false;
  255.     }
  256.  
  257.     if (notFlag)
  258.     {
  259.     newCond ^= 1;        /* toggle condition true/false */
  260.     notFlag = false;    /* reset not flag for next condition */
  261.     }
  262.  
  263.     if (orFlag)
  264.     {
  265.     /* if the condition is true then update condition to true. */
  266.     if (newCond) cond = true;
  267.     orFlag =